package com.ztf.jsonTest;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.XML;
import com.alibaba.fastjson2.JSON;
import org.apache.commons.io.IOUtils;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.XMLWriter;
import org.json.JSONArray;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.XMLFilterImpl;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.transform.Source;
import javax.xml.transform.sax.SAXSource;
import java.io.StringReader;
import java.io.StringWriter;
import java.sql.Struct;

/**
 * @author lengleng
 * @date 2018年02月02日10:47:17
 */
public class YjXmlUtils {

    private final static String SUCCESS = "COMPLETE";

    public static <T> T XML2Object(Class<T> clazz, String xml) {
        try {
            if (xml == null) {
                return null;
            }
            JAXBContext ctx = JAXBContext.newInstance(clazz);
            Unmarshaller unmarshaller = ctx.createUnmarshaller();

            StringReader reader = new StringReader(xml);
            SAXParserFactory sax = SAXParserFactory.newInstance();
            sax.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
            sax.setNamespaceAware(false);
            XMLReader xmlReader = sax.newSAXParser().getXMLReader();
            Source source = new SAXSource(xmlReader, new InputSource(reader));
            Object result = unmarshaller.unmarshal(source);
            return (T) result;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static <T> String object2XML(T t, String charset) {
        String result = null;
        StringWriter writer = new StringWriter();
        try {
            JAXBContext jaxbContext = JAXBContext.newInstance(t.getClass());
            Marshaller marshaller = jaxbContext.createMarshaller();
            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, false);
            marshaller.setProperty(Marshaller.JAXB_ENCODING, charset);
            OutputFormat format = new OutputFormat();
            format.setEncoding(charset);
            format.setIndent(false);
            format.setNewlines(false);
            format.setNewLineAfterDeclaration(false);
            XMLWriter xmlWriter = new XMLWriter(writer, format);
            xmlWriter.setEscapeText(false);
            XMLFilterImpl nsFilter = new XMLFilterImpl() {
                private boolean ignoreNamespace = false;
                //				private String rootNamespace = null;
                private boolean isRootElement = true;

                @Override
                public void startPrefixMapping(String prefix, String url) throws SAXException {
                    if (!this.ignoreNamespace) {
                        super.startPrefixMapping("", url);
                    }
                }

                @Override
                public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
                    if (this.ignoreNamespace) {
                        uri = "";
                    }
                    if (this.isRootElement) {
                        this.isRootElement = false;
                    } else if (!"".equals(uri) && !"xmlns".contains(localName)) {
                        localName = localName + " xmlns=\"" + uri + "\"";
                    }
                    super.startElement(uri, localName, localName, attributes);
                }

                @Override
                public void endElement(String uri, String localName, String qName) throws SAXException {
                    if (this.ignoreNamespace) {
                        uri = "";
                    }
                    super.endElement(uri, localName, localName);
                }

            };

            nsFilter.setContentHandler(xmlWriter);
            marshaller.marshal(t, nsFilter);
            result = writer.toString();
        } catch (Exception ex) {

        } finally {
            IOUtils.closeQuietly(writer);
        }
        return result;
    }

    public static <T> T parseEsbXml(String res, Class<T> clazz) throws Exception {
        JSONObject json = XML.toJSONObject(res);
        JSONObject serviceResponse = json.getJSONObject("Service").getJSONObject("Service_Header").getJSONObject("service_response");
        JSONObject extAttributes = json.getJSONObject("Service").getJSONObject("Service_Body").getJSONObject("ext_attributes");
        JSONObject responseBody = json.getJSONObject("Service").getJSONObject("Service_Body").getJSONObject("response");
        responseBody.put("code",serviceResponse.getStr("code"));
        responseBody.put("status",serviceResponse.getStr("status"));
        responseBody.put("desc",serviceResponse.getStr("desc"));
        JSONObject opmPageCtl = extAttributes.getJSONObject("OPM-PAGE-CTL");
        if(null!=opmPageCtl){
            String opmPageStaKey = opmPageCtl.getStr("OPM-PAGE-STA-KEY");
            String opmPageEndKey = opmPageCtl.getStr("OPM-PAGE-END-KEY");
            String opmPageNoData = opmPageCtl.getStr("OPM-PAGE-NO-DATA");
            responseBody.put("opmPageStaKey",opmPageStaKey);
            responseBody.put("opmPageEndKey",opmPageEndKey);
            responseBody.put("opmPageNoData",opmPageNoData);
            if (StrUtil.isNotBlank(opmPageNoData) && "1".equals(opmPageNoData)) {
                responseBody.put("hasNextPage",false);
            } else {
                responseBody.put("hasNextPage",true);
            }
        }
        if (SUCCESS.equals(serviceResponse.getStr("status"))) {
             String str =  responseBody.getStr("LN-LN-GRP");
             if(!str.startsWith("[")){
                 str = "["+str+"]";
                 responseBody.set("LN-LN-GRP", JSON.parseArray(str));
             }
            T resOut = com.alibaba.fastjson.JSONObject.parseObject(responseBody.toString(), clazz);
            return resOut;
        } else {
            throw new RuntimeException("核心接口返回失败，【status】:" + serviceResponse.getStr("status")
                    + "【code】:" + serviceResponse.getStr("code")
                    + "【desc】:" + serviceResponse.getStr("desc"));
        }
    }
}
